package org.springframework.core.type;

import org.springframework.core.util.AnnotatedElementUtils;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;

/**
 * @author:刘仁有
 * @desc:
 * @email:953506233@qq.com
 * @data:2019/12/14
 */
public class StandardAnnotationMetadata extends StandardClassMetadata implements AnnotationMetadata  {

    private final Annotation[] annotations;

    public StandardAnnotationMetadata(Class<?> introspectedClass) {
        super(introspectedClass);
        this.annotations = introspectedClass.getAnnotations();
    }

    @Override
    public Set<String> getAnnotationTypes() {
        Set<String> types = new LinkedHashSet<>();
        for (Annotation ann : this.annotations) {
            types.add(ann.annotationType().getName());
        }
        return types;
    }


    @Override
    public boolean hasAnnotation(Class<? extends Annotation> annotationType) {
        for (Annotation ann : this.annotations) {
            if (ann.annotationType().equals(annotationType)) {
                return true;
            }
        }
        return false;
    }


    @Override
    public boolean hasAnnotatedMethods(Class<? extends Annotation> annotationType) {
        Method[] methods = getIntrospectedClass().getDeclaredMethods();
        for (Method method : methods) {
            if (!method.isBridge() && method.getAnnotations().length > 0 &&
                    AnnotatedElementUtils.isAnnotated(method, annotationType)) {
                return true;
            }
        }
        return false;
    }

    @Override
    public Set<MethodMetadata> getAnnotatedMethods(Class<? extends Annotation> annotationType) {
        Method[] methods = getIntrospectedClass().getDeclaredMethods();
        Set<MethodMetadata> annotatedMethods = new LinkedHashSet<>(4);
        for (Method method : methods) {
            if (!method.isBridge() && method.getAnnotations().length > 0 &&
                    AnnotatedElementUtils.isAnnotated(method, annotationType)) {
                annotatedMethods.add(new StandardMethodMetadata(method));
            }
        }
        return annotatedMethods;
    }


    @Override
    public boolean isAnnotated(Class<? extends Annotation> annotationType) {
        return (this.annotations.length > 0 &&
                AnnotatedElementUtils.isAnnotated(getIntrospectedClass(), annotationType));
    }

    @Override
    public Map<String, Object> getAnnotationAttributes(Class<? extends Annotation> annotationType) {
        return getAnnotationAttributes(annotationType,false);
    }

    @Override
    public Map<String, Object> getAnnotationAttributes(Class<? extends Annotation> annotationType, boolean classValuesAsString) {
        return (this.annotations.length > 0 ? AnnotatedElementUtils.getAnnotationAttributes(
                getIntrospectedClass(), annotationType, classValuesAsString) : new HashMap<String,Object>());
    }


    public Annotation[] getAnnotations() {
        return annotations;
    }
}
